#ifndef __MBlock_h__
#define __MBlock_h__

#include <assert.h>
#include <string.h>
#include <algorithm>

#include "Base/Types.h"
#include "Thread/Lock.h"

class MBlock
{
private:
	unsigned char * pData;
	SizeType iRealSize;
	SizeType * iCount;
	bool bModified;

	void free()
	{
		if((NULL != iCount)&&(0 == (--(*iCount))))
		{
			if(NULL != pData)
			{
				::free(pData);
				pData = NULL;
			};
			delete iCount;
			iCount = NULL;
			delete myLock;
			myLock = NULL;
		};
	};

	void assign(const MBlock & from)
	{
		assert(NULL == pData);
		assert(NULL == iCount);
		assert(NULL == myLock);
		pData = from.pData;
		iRealSize = from.iRealSize;
		iCount = from.iCount;
		if(NULL != iCount);
			++(*iCount);
		myLock = from.myLock;
	};
public:
	mutable LockImpl * myLock;

	MBlock(const void * data = NULL, SizeType realSize = 0) : pData(NULL), iRealSize(0), iCount(NULL), myLock(NULL)
	{ 
		if(NULL != data)
	 	{
			assert(realSize <= MBLOCK_DEFAULT_SIZE);
			iRealSize = realSize;
			pData = reinterpret_cast<unsigned char*>(malloc(MBLOCK_DEFAULT_SIZE));
			memcpy(pData, data, realSize);
			iCount = new SizeType(1);
			myLock = new LockImpl;
		};
	};

	~MBlock()
	{
		free();
	};

	MBlock(const MBlock & from) : pData(NULL), iRealSize(0), iCount(NULL), myLock(NULL)
	{
		assign(from);
	};

	MBlock& operator=(const MBlock & from)
	{
		free();
		assign(from);
		return * this;
	};

	SizeType getRealSize() const
	{
		return iRealSize;
	};

	template <typename FuncType, typename RetType>
	RetType ReadData(FuncType op, const RetType &) const
	{
		ReadLock _(*myLock);
		return op(pData, iRealSize);
	};

	template <typename FuncType>
	void ReadData(FuncType op) const
	{
		ReadLock _(*myLock);
		op(pData, iRealSize);
	};

	bool isModified() const
	{
		return bModified;
	};

	void setUnchanged()
	{
		bModified = false;
	};

	bool read(void * out, SizeType begin, SizeType len) const
	{
		ReadLock _(*myLock);
		if(begin + len > iRealSize)
			return false;
		memcpy(out, pData + begin, len);
		return true;
	};

	bool write(const void * out, SizeType begin, SizeType len)
	{
		WriteLock _(*myLock);
		if((begin > iRealSize)||(begin + len > MBLOCK_DEFAULT_SIZE))
			return false;
		memcpy(pData + begin, out, len);
		iRealSize = std::max(begin + len, iRealSize);
		bModified = true;
		return true;
	};
};


#endif

